iT邦幫忙

2026 iThome 鐵人賽

DAY 15
1
Software Development

從 C++ 菜鳥到 Low-Latency 勇者:一場分秒必爭的賽局系列 第 15

[Day 15] High-Performance Concurrency: Memory Models & Ordering

  • 分享至 

  • xImage
  •  

False Sharing Prevention 中有提到其與 std::atomic 之間的關係。而在高效能並行程式設計中,真正困難的不只是熟悉 atomic 的使用時機,而是理解 memory model 如何影響不同 thread 之間的資料可見性記憶體操作順序,選擇適當的 memory ordering

atomic 用來安全地進行跨執行緒的資料共享,避免對特定物件產生 data race;而 memory ordering 決定不同 thread 之間應該以什麼程度的順序來觀察這些操作。當多個 thread 同時存取共享資料時,CPU 與編譯器可能會重新排序指令。因此程式碼撰寫的先後順序,不一定代表其他 thread 實際觀察到的順序。

1. Sequential Consistency

最直觀的模型是 sequential consistency。可以想像成所有 thread 的操作都被排列在某一個全域順序中,並且每個 thread 自己的操作順序也會被保留,因此執行情況相對容易理解與推理。

不過為了追求更高的效能,現代 CPU 通常不需要對所有 memory operation 都維持如此嚴格的全域順序。過度強制 memory ordering,可能需要額外的 memory barrier,進而限制 CPU 與 compiler 進行 instruction reordering 和其他最佳化的空間。

2. Acquire-Release Semantics

正因上述提到的限制,在實務上的 concurrent programming 中,更常見的是 Acquire-Release semantics。

release 通常用來表示在這個操作之前的 memory operation 必須先完成,並且其結果可以被其他同步的 thread 看到;而 acquire 則確保一旦取得對應的同步狀態後,可以看到對方在 release 之前完成的操作。這讓不同 thread 可以在需要同步的地方建立明確的 happens-before 關係,同時避免不必要的全域記憶體排序。

例如,一個執行緒先完成資料初始化,再透過 atomic flag 發出通知;另一個執行緒使用 acquire 讀取這個 flag。這樣就能確保看到 flag 更新的執行緒,也能正確看到之前初始化的資料。相比單純使用最強的 sequential consistency,這種方式通常能在維持正確性並保證同步的前提下,依然給編譯器與 CPU 更多的硬體優化空間。

Thread AㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤThread B

初始化資料
ㅤㅤ↓
data = 42
ㅤㅤ↓
flag.store(true, release)
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ↓
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤflag.load(acquire)
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ↓
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ讀取 data

在低延遲的程式設計中,memory ordering 並不是越強越好。過度的同步限制可能帶來額外成本,限制 CPU 的執行效率;而過弱的 ordering 則可能導致難以察覺的 concurrency bug。因此,理解 memory model 是走向高效能且正確的 lock-free / concurrent code 的重要基礎。尤其在高頻交易這類對 latency 極度敏感的場景中,這些細節往往更加重要。


上一篇
[Day 14] High-Performance Concurrency: False Sharing Prevention
下一篇
[Day 16] High-Performance Concurrency: Lock-Free Programming I
系列文
從 C++ 菜鳥到 Low-Latency 勇者:一場分秒必爭的賽局21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言